package middleware

import (
	"bytes"
	"chinaport-proxy/auth"
	"io"
	"log/slog"
	"net/http"
	"strconv"

	"github.com/gin-gonic/gin"
)

// AuthMiddleware creates an authentication middleware
func AuthMiddleware(appSecret string) gin.HandlerFunc {
	return func(c *gin.Context) {
		// If appSecret is empty, authentication is disabled
		if appSecret == "" {
			c.Next()
			return
		}

		// Get required headers
		timestampStr := c.GetHeader("X-Timestamp")
		signature := c.GetHeader("X-Signature")

		// Check if headers are present
		if timestampStr == "" || signature == "" {
			slog.Warn("Missing authentication headers",
				"path", c.Request.URL.Path,
				"remote_addr", c.ClientIP())
			c.JSON(http.StatusUnauthorized, gin.H{
				"error": "Missing authentication headers",
			})
			c.Abort()
			return
		}

		// Parse timestamp
		timestamp, err := strconv.ParseInt(timestampStr, 10, 64)
		if err != nil {
			slog.Warn("Invalid timestamp format",
				"timestamp", timestampStr,
				"error", err)
			c.JSON(http.StatusUnauthorized, gin.H{
				"error": "Invalid timestamp format",
			})
			c.Abort()
			return
		}

		// Check timestamp validity (within 3 seconds)
		if !auth.IsTimestampValid(timestamp, 3) {
			slog.Warn("Timestamp expired",
				"timestamp", timestamp,
				"remote_addr", c.ClientIP())
			c.JSON(http.StatusUnauthorized, gin.H{
				"error": "Timestamp expired",
			})
			c.Abort()
			return
		}

		// Read body for signature validation
		bodyBytes, err := io.ReadAll(c.Request.Body)
		if err != nil {
			slog.Error("Failed to read request body", "error", err)
			c.JSON(http.StatusInternalServerError, gin.H{
				"error": "Failed to read request body",
			})
			c.Abort()
			return
		}

		// Restore body for downstream handlers
		c.Request.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))

		// Validate signature
		if !auth.ValidateSignature(
			c.Request.Method,
			c.Request.URL.Path,
			timestamp,
			string(bodyBytes),
			appSecret,
			signature,
		) {
			slog.Warn("Invalid signature",
				"path", c.Request.URL.Path,
				"remote_addr", c.ClientIP())
			c.JSON(http.StatusUnauthorized, gin.H{
				"error": "Invalid signature",
			})
			c.Abort()
			return
		}

		// Authentication successful
		c.Next()
	}
}
